/*
 * @Author: FBB
 * @Date: 2020-06-03 13:44:29
 * @LastEditors: FBB
 * @LastEditTime: 2020-06-03 15:06:20
 * @Description: 判断两个对象是否相等，尚未判断构造函数对象和循环引用
 * 
 * https://github.com/mqyqingfeng/Blog/issues/41
 */

function eq(a, b) {
  //处理a/b为null的情况
  if (a === null && b === null) return true;
  if (a === null || b === null) return false;
  //判断0和-0
  if (a === b) return a !== 0 || 1 / a === 1 / b;
  //判断NaN
  if (a !== a) return b !== b;
  //如果a是基本类型就返回false，否则进行深入比较
  if (typeof a !== "function" && typeof a !== "object" && typeof b !== "object")
    return false;
  return deepEq(a, b);
}

function deepEq(a, b) {
  //处理基础类型和封装类型
  const toString = Object.prototype.toString;
  const className = toString.call(a);
  if (className !== toString.call(b)) return false;
  switch (className) {
    case "[object RegExp]":
    case "[object String]":
      return "" + a === "" + b;
    case "[object Number]":
      if (+a !== +a) return +b !== +b;
      return +a === 0 ? 1 / +a === 1 / b : +a === +b;
    case "[object Date]":
    case "[object Boolean]":
      return +a === +b;
  }
  const isArray = className === "[object Array]";
  //数组
  if (isArray) {
    let length = a.length;
    if (length !== b.length) return false;
    while (length--) {
      if (!eq(a[length], b[length])) return false;
    }
  }
  //对象
  else {
    const keys = Object.keys(a);
    let length = keys.length;
    if (Object.keys(b).length !== length) return false;
    if (length--) {
      let key = keys[length];
      if (!(b.hasOwnProperty(key) && eq(a[key], b[key]))) return false;
    }
  }
  return true;
}
